//MouseDevice.java
//John Hopf (Summer, 2002)

//Merged Itchy/Scratchy code - Benjamin Avery
//19 August 2003

import javax.comm.*;
import javax.swing.event.MouseInputListener;

import tracker.TrackerFastrak;
import tracker.TrackerIsotrakII;
import tracker.TrackerPolhemus;

import java.awt.Component;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.util.*;

public abstract class ButtonDevice {

	public static final int FORWARD_BUTTON = 0;
	public static final int PRIMARY_PICKING_BUTTON = 1;
	public static final int SECONDARY_PICKING_BUTTON = 6;
	public static final int BACKWARD_BUTTON = 3;
	public static final int STRAFE_LEFT_BUTTON = 4;
	public static final int STRAFE_RIGHT_BUTTON = 2;
	public static final int LEVITATE_UP_BUTTON = 8;
	public static final int LEVITATE_DOWN_BUTTON = 9;
	
	
	/** a factory method that returns an instance of a button device 
	 *  for a given tracker. This is the preferred way to retrieve 
	 *  a button device.  */
	public static ButtonDevice getButtonDeviceForTracker(TrackerPolhemus tracker){
		if (tracker instanceof TrackerIsotrakII)
			return new ScratchyDevice(tracker);
		else if (tracker instanceof TrackerFastrak)
			return new ItchyDevice(tracker);
		return null;
	}
	
	public static ButtonDevice getConventionalControlDeviceForAWTComponent(Component c, boolean useMouse){
		if (useMouse)
			return new MouseAndKeyboardDevice(c);
		return new KeyboardDevice(c);
	}
	
	public abstract boolean getButton(int button);
	
}

/********************************************************************/
/**                    KeyboardControl Class                       **/
/********************************************************************/
class KeyboardDevice extends ButtonDevice implements KeyListener {
	
	private static int[] KEY_FORWARD       = VR.getKeyCodeForKeyboardControl("forward");
	private static int[] KEY_BACKWARD      = VR.getKeyCodeForKeyboardControl("backward");
	private static int[] KEY_PRIMARYPICK   = VR.getKeyCodeForKeyboardControl("primary_pick");
	private static int[] KEY_STRAFE_LEFT   = VR.getKeyCodeForKeyboardControl("strafe_left");
	private static int[] KEY_STRAFE_RIGHT  = VR.getKeyCodeForKeyboardControl("strafe_right");
	private static int[] KEY_LEVITATE_UP   = VR.getKeyCodeForKeyboardControl("levitate_up");
	private static int[] KEY_LEVITATE_DOWN = VR.getKeyCodeForKeyboardControl("levitate_down");

	protected boolean keystate[] = {
			false, /* forward */
			false, /* primary pick */
			false, /* strafe right */
			false, /* backward */
			false, /* strafe left */
			false, /* levitate up */
			false, /* levitate down */
			false, 
			false, 
			false
	};
	
	public KeyboardDevice(Component keySource){
		keySource.addKeyListener(this);
	}
	
	/** mappings between hardware and software buttons are different
	 * on the two machines, so we need methods to handle each case.
	 */
	public boolean getButton(int button){		
		return keystate[button];
	}

	public int idxForKey(KeyEvent e){
		int c = e.getKeyCode();
		if (VR.contains(KEY_FORWARD, c))
			return FORWARD_BUTTON;
		if (VR.contains(KEY_BACKWARD, c))
			return BACKWARD_BUTTON;
		if (VR.contains(KEY_PRIMARYPICK, c))
			return PRIMARY_PICKING_BUTTON;
		if (VR.contains(KEY_STRAFE_LEFT, c))
			return STRAFE_LEFT_BUTTON;
		if (VR.contains(KEY_STRAFE_RIGHT, c))
			return STRAFE_RIGHT_BUTTON;
		if (VR.contains(KEY_LEVITATE_DOWN, c))
			return LEVITATE_DOWN_BUTTON;
		if (VR.contains(KEY_LEVITATE_UP, c))
			return LEVITATE_UP_BUTTON;
		return -1;
	}
	
	public void keyPressed(KeyEvent e) { 
		int idx = idxForKey(e);
		if (idx != -1)
			keystate[idx] = true;
	}

	public void keyReleased(KeyEvent e) {
		int idx = idxForKey(e);
		if (idx != -1)
			keystate[idx] = false;
	}

	/* ignored handlers */
	public void keyTyped(KeyEvent e) { }

}


/********************************************************************/
/**                Mouse and Keyboard Control Class                **/
/********************************************************************/
class MouseAndKeyboardDevice extends KeyboardDevice implements MouseInputListener {

	private boolean mouseButtonState = false;
	
	public MouseAndKeyboardDevice(Component mouseSource){
		super(mouseSource);
		mouseSource.addMouseListener(this);
	}
	
	/** mappings between hardware and software buttons are different
	 * on the two machines, so we need methods to handle each case.
	 */
	public boolean getButton(int button){		
		if (button == PRIMARY_PICKING_BUTTON && mouseButtonState)
			return true;
		return keystate[button];
	}
	
	public void mousePressed(MouseEvent arg0) { 
		mouseButtonState = true;
	}
	
	public void mouseReleased(MouseEvent arg0) { 
		mouseButtonState = false;
	}

	/* ignored handlers */
	public void mouseClicked(MouseEvent arg0) { }
	public void mouseEntered(MouseEvent arg0) {	}
	public void mouseExited(MouseEvent arg0) { }
	public void mouseDragged(MouseEvent arg0) { }
	public void mouseMoved(MouseEvent arg0) { }	
}


/********************************************************************/
/**                  Tracker button Control Class                  **/
/********************************************************************/
abstract class TrackerButtonDevice extends ButtonDevice {
	
	private static CommPortIdentifier portId;
	
	private static Enumeration portList;
	
	private static final String COMPORT_NAME = "COM2";
	
	protected static ButtonDeviceSerialPort reader;
	
	
	protected TrackerButtonDevice(TrackerPolhemus tracker) {

		/*If keyboard mode enabled we don't use the mouse device */
		portList = CommPortIdentifier.getPortIdentifiers();
		while (portList.hasMoreElements()) {
			portId = (CommPortIdentifier) portList.nextElement();
			if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL)
				if (portId.getName().equals(COMPORT_NAME)){
					reader = new ButtonDeviceSerialPort(portId);
					if (portId != null && portId.getName() != null)
						System.out.println("===>" + portId.getName());				
				}
		}
	}
}


class ScratchyDevice extends TrackerButtonDevice {
	
	public ScratchyDevice(TrackerPolhemus tracker){
		super(tracker);
	}
	
	/** mappings between hardware and software buttons are different
	 * on the two machines, so we need methods to handle each case.
	 */
	public boolean getButton(int button){		
		switch (button){
		case 0: // forward
			return (reader.getButton7());
		case 1: // primary picking button
			return (reader.getButton6());
		case 2: // strafe right
			return (reader.getButton5());
		case 3: // backwards
			return (reader.getButton8());
		case 4: // strafe left
			return (reader.getButton4());
		case 5: 
			return (reader.getButton1());
		case 6: // secondary picking button
			return (reader.getButton2());
		case 7:
			return (reader.getButton3());
		case 8:
			return (reader.getButton9());
		case 9:
			return (reader.getButton10());
		default:
			return false;
		}
	}	
}


class ItchyDevice extends TrackerButtonDevice {
	
	public ItchyDevice(TrackerPolhemus tracker){
		super(tracker);
	}
	
	/** mappings between hardware and software buttons are different
	 * on the two machines, so we need methods to handle each case.
	 */
	public boolean getButton(int button){		
		switch (button){
		case 0:
			return (reader.getButton1());
		case 1:
			return (reader.getButton4());
		case 2:
			return (reader.getButton3());
		case 3:
			return (reader.getButton2());
		case 4:
			return (reader.getButton5());
		case 5:
			return (reader.getButton6());
		case 6:
			return (reader.getButton8());
		case 7:
			return (reader.getButton7());
		case 8:
			return (reader.getButton9());
		case 9:
			return (reader.getButton10());
		default:
			return false;
		}		
	}
}